package com.yfkj.sms.redis.service.impl;

import com.alibaba.fastjson.JSON;
import com.google.common.collect.Lists;
import com.yfkj.sms.redis.service.YfkjSmsRedisService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.dubbo.config.annotation.DubboService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;

import java.sql.Timestamp;
import java.util.*;
import java.util.concurrent.TimeUnit;

/**
 * @ClassName YfkjSmsRedisServiceImpl
 * @Description redis 服务
 * @Author mzb
 * @Date 2020/11/22 16:58
 * @Version V1.0.0
 */
@DubboService(version = "1.0.0")
@SuppressWarnings("unchecked")
@Slf4j
public class YfkjSmsRedisServiceImpl implements YfkjSmsRedisService {

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    private final String defaultKeySpace = "smsRoot";
    private final String nameSpaceSplitChar = "/";

    private final String LOCK_REDIS_PREFIX = "redis_lock_";

    /**
     * 方法作用描述
     * 保存String类型的数据
     *
     * @param key   :
     * @param value :
     * @return void
     * @author mzb
     */
    @Override
    public boolean setStr(String key, String value) {
        return this.putVal(defaultKeySpace, key, value, null);
    }

    /**
     * 方法作用描述
     * 保存string类型 带过期时间
     *
     * @param key        :
     * @param value      :
     * @param expireTime :
     * @return void
     * @author mzb
     */
    @Override
    public boolean setStrExpire(String key, String value, Integer expireTime) {
        return this.putVal(defaultKeySpace, key, value, expireTime);
    }

    /**
     * 方法作用描述
     * 取值 string 类型
     *
     * @param key :
     * @return java.lang.String
     * @author mzb
     */
    @Override
    public String getVal(String key) {
        if (StringUtils.isEmpty(key)) {
            log.info("无法获取缓存数据，key值为" + key);
            return "";
        }
        return this.getVal(defaultKeySpace, key);
    }

    @Override
    public boolean putVal(String key, Object value) {
        if (StringUtils.isEmpty(key) || value == null) {
            log.info("putVal()key或value或namespace参数为空,不做保存处理!");
            return false;
        }
        return this.putVal(defaultKeySpace, key, value);
    }

    @Override
    public boolean putVal(String nameSpace, String key, Object value) {
        return this.putVal(nameSpace, key, value, null);
    }

    /**
     * 方法作用描述
     *
     * @param nameSpace  : 空间 前缀
     * @param key        :       key值
     * @param value      :
     * @param expireTime : 过期时间
     * @return boolean
     * @author mzb
     */
    @Override
    public boolean putVal(String nameSpace, String key, Object value, Integer expireTime) {
        if (key == null || key.trim().length() == 0 || StringUtils.isEmpty(nameSpace) || null == value) {
            log.info("putVal()key或value或namespace参数为空,不做保存处理!");
            return false;
        }

        String val = null;
        if (!(value instanceof String) && !(value instanceof Number) && !(value instanceof Boolean) && !(value instanceof Date) && !(value instanceof Timestamp) && !(value instanceof java.sql.Date)) {
            val = JSON.toJSONString(value);
        } else {
            val = value.toString();
        }
        key = nameSpace + nameSpaceSplitChar + key;
        if (expireTime != null) {
            stringRedisTemplate.opsForValue().set(key, val, expireTime, TimeUnit.SECONDS);
        } else {
            stringRedisTemplate.opsForValue().set(key, val);
        }
        return true;
    }

    /**
     * 方法作用描述
     * 返回数据 String类型
     *
     * @param nameSpace :
     * @param key       :
     * @return java.lang.String
     * @author mzb
     */
    @Override
    public String getVal(String nameSpace, String key) {
        if (StringUtils.isNotEmpty(nameSpace)) {
            key = nameSpace + nameSpaceSplitChar + key;
        }
        return stringRedisTemplate.opsForValue().get(key);
    }

    @Override
    public boolean existKey(String nameSpace, String key) {
        if (StringUtils.isNotBlank(nameSpace) && StringUtils.isNotBlank(key)) {
            key = nameSpace + nameSpaceSplitChar + key;
        }
        return redisTemplate.hasKey(key);
    }

    @Override
    public boolean existKey(String key) {
        return this.existKey(defaultKeySpace, key);
    }

    @Override
    public boolean setCacheExpire(String key, int expireTime) {
        return this.setCacheExpire(defaultKeySpace, key, expireTime);
    }

    @Override
    public boolean setCacheExpire(String nameSpace, String key, int expireTime) {
        if (StringUtils.isNotBlank(nameSpace) && StringUtils.isNotBlank(key)) {
            key = nameSpace + nameSpaceSplitChar + key;
        }
        redisTemplate.expire(key, expireTime, TimeUnit.SECONDS);
        return false;
    }


    /**
     * 方法描述: 根据key删除指定的缓存（无空间）
     *
     * @param key :
     * @return: java.lang.Boolean
     */
    @Override
    public Boolean del(String key) {
        return redisTemplate.delete(key);
    }

    /**
     * 加锁
     *
     * @param key   - 唯一标志
     * @param value 当前时间+超时时间 也就是时间戳 毫秒
     * @return
     */
    @Override
    public boolean lock(String key, String value) {
        String redisKey = LOCK_REDIS_PREFIX + key;
        if (stringRedisTemplate.opsForValue().setIfAbsent(redisKey, value)) {
            return true;
        }
        String currentValue = stringRedisTemplate.opsForValue().get(redisKey);
        if (!StringUtils.isEmpty(currentValue) && Long.parseLong(currentValue) < System.currentTimeMillis()) {
            String oldValue = stringRedisTemplate.opsForValue().getAndSet(redisKey, value);
            return StringUtils.isNotEmpty(oldValue) && oldValue.equals(currentValue);
        }
        return false;
    }

    /**
     * 解锁
     *
     * @param key   锁键
     * @param value 锁键的value
     */
    @Override
    public void unLock(String key, String value) {
        String redisKey = LOCK_REDIS_PREFIX + key;
        try {
            String currentValue = stringRedisTemplate.opsForValue().get(redisKey);
            if (!StringUtils.isEmpty(currentValue) && currentValue.equals(value)) {
                stringRedisTemplate.opsForValue().getOperations().delete(redisKey);
            }
        } catch (Exception e) {
            log.info("解锁失败,key:" + redisKey + " value:" + value);
        }

    }
}
